home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / clients / xmag / scale.c < prev    next >
Text File  |  1994-08-12  |  28KB  |  1,028 lines

  1. /*
  2.  * $XConsortium: Scale.c,v 1.15 91/08/26 11:00:15 gildea Exp $
  3.  *
  4.  * Copyright 1989 Massachusetts Institute of Technology
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of M.I.T. not be used in advertising or
  11.  * publicity pertaining to distribution of the software without specific,
  12.  * written prior permission.  M.I.T. makes no representations about the
  13.  * suitability of this software for any purpose.  It is provided "as is"
  14.  * without express or implied warranty.
  15.  *
  16.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  17.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  18.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  20.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  21.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  *
  23.  * Author:  Davor Matic, MIT X Consortium
  24.  */
  25.  
  26.  
  27. #include <stdio.h>
  28. #include <ctype.h>
  29. #include <string.h> 
  30. #include <math.h>
  31. #ifdef MSDOS
  32. #include "X11/IntrinsP.h"      /* QDK 05/17/1994  4:19pm. */
  33. #else
  34. #include "X11/IntrinsicP.h"
  35. #endif
  36. #include <X11/StringDefs.h>
  37. #include <X11/Xaw/XawInit.h>
  38. #include "ScaleP.h"
  39. #include <X11/Xosdefs.h>
  40.  
  41. #define myrint(x) floor(x + 0.5)
  42.  
  43. #ifndef X_NOT_STDC_ENV
  44. #include <stdlib.h>
  45. #endif
  46.  
  47. #if defined(ISC) && defined(SYSV) && defined(SYSV386) && __STDC__
  48. extern double atof(char *);
  49. #endif
  50.  
  51. #define streq(a,b) (strcmp( (a), (b) ) == 0)
  52. #if !defined(__WATCOMC__)
  53. #define min(x, y) (x > y ? y : x)
  54. #define max(x, y) (x < y ? y : x)
  55. #endif
  56.  
  57. #define DefaultBufferSize 1024
  58. #define DefaultScaleFactor NULL
  59.  
  60. #define Offset(field) XtOffsetOf(ScaleRec, scale.field)
  61.  
  62. static XtResource resources[] = {
  63. {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  64.      Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground},
  65. {XtNgravity, XtCGravity, XtRGravity, sizeof(XtGravity),
  66.      Offset(gravity), XtRImmediate, (XtPointer) "ForgetGravity"},
  67. {XtNinternalWidth, XtCWidth, XtRDimension,  sizeof(Dimension),
  68.      Offset(internal_width), XtRImmediate, (XtPointer) 2},
  69. {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
  70.      Offset(internal_height), XtRImmediate, (XtPointer) 2},
  71. {XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
  72.      Offset(resize), XtRImmediate, (XtPointer) True},
  73. {XtNautoscale, XtCAutoscale, XtRBoolean, sizeof(Boolean),
  74.      Offset(autoscale), XtRImmediate, (XtPointer) True},
  75. {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean),
  76.      Offset(proportional), XtRImmediate, (XtPointer) True},
  77. {XtNscaleX, XtCScaleFactor, XtRString, sizeof(String),
  78.      Offset(scale_x_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  79. {XtNscaleY, XtCScaleFactor, XtRString, sizeof(String),
  80.      Offset(scale_y_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  81. {XtNaspectRatio, XtCAspectRatio, XtRString, sizeof(String),
  82.      Offset(aspect_ratio_str), XtRImmediate, (XtPointer) "1.0"},
  83. {XtNprecision, XtCPrecision, XtRString, sizeof(String),
  84.      Offset(precision_str), XtRImmediate, (XtPointer) "0.001"},
  85. {XtNimage, XtCImage, XtRImage, sizeof(XImage*),
  86.      Offset(image), XtRImmediate, (XtPointer) NULL},
  87. {XtNpasteBuffer, XtCPasteBuffer, XtRBoolean, sizeof(Boolean),
  88.      Offset(paste_buffer), XtRImmediate, (XtPointer) False},
  89. {XtNbufferSize, XtCBufferSize, XtRCardinal, sizeof(Cardinal),
  90.      Offset(buffer_size), XtRImmediate, (XtPointer) DefaultBufferSize},
  91. {XtNuserData, XtCuserData, XtRuserData, sizeof(XtPointer),
  92.      Offset(userData), XtRImmediate, (XtPointer) NULL},
  93. { XtNvisual, XtCvisual, XtRVisual, sizeof(Visual*),
  94.      Offset(visual), XtRImmediate, CopyFromParent}
  95. };
  96.  
  97. #undef Offset
  98.  
  99. static void ClassInitialize();
  100. static void Initialize();
  101. static void Realize();
  102. static void Redisplay();
  103. static void Resize();
  104. static void Destroy();
  105. static Boolean SetValues();
  106.  
  107. void SWUnscale();
  108. void SWAutoscale();
  109. void SWInitialSize();
  110. void RequestSelection();
  111. void GrabSelection();
  112.  
  113. static XtActionsRec actions[] =
  114. {
  115. {"unscale", SWUnscale},
  116. {"autoscale", SWAutoscale},
  117. {"initial-size", SWInitialSize},
  118. {"paste", RequestSelection},
  119. {"cut", GrabSelection}
  120. };
  121.  
  122. static char translations[] =
  123. "\
  124.  <Key>u:           unscale()\n\
  125.  <Key>a:           autoscale()\n\
  126.  <Key>i:           initial-size()\n\
  127. ";
  128.  
  129. ScaleClassRec scaleClassRec = {
  130. {   /* core fields */
  131.     /* superclass        */    (WidgetClass) &simpleClassRec,
  132.     /* class_name        */    "Scale",
  133.     /* widget_size        */    sizeof(ScaleRec),
  134.     /* class_initialize        */    ClassInitialize,
  135.     /* class_part_initialize    */    NULL,
  136.     /* class_inited        */    FALSE,
  137.     /* initialize        */    Initialize,
  138.     /* initialize_hook        */    NULL,
  139.     /* realize            */    Realize,
  140.     /* actions            */    actions,
  141.     /* num_actions        */    XtNumber(actions),
  142.     /* resources        */    resources,
  143.     /* num_resources        */    XtNumber(resources),
  144.     /* xrm_class        */    NULLQUARK,
  145.     /* compress_motion        */    TRUE,
  146.     /* compress_exposure    */      XtExposeCompressMaximal|
  147.                                         XtExposeGraphicsExposeMerged,
  148.     /* compress_enterleave    */    TRUE,
  149.     /* visible_interest        */    TRUE,
  150.     /* destroy            */    Destroy,
  151.     /* resize            */    Resize,
  152.     /* expose            */    Redisplay,
  153.     /* set_values        */    SetValues,
  154.     /* set_values_hook        */    NULL,
  155.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  156.     /* get_values_hook        */    NULL,
  157.     /* accept_focus        */    NULL,
  158.     /* version            */    XtVersion,
  159.     /* callback_private        */    NULL,
  160.     /* tm_table            */      translations,
  161.     /* query_geometry        */    XtInheritQueryGeometry,
  162.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  163.     /* extension        */    NULL
  164.   },
  165.   { 
  166.     /* change_sensitive        */    XtInheritChangeSensitive,
  167.   }
  168. };
  169.  
  170. WidgetClass scaleWidgetClass = (WidgetClass) &scaleClassRec;
  171.     
  172.  
  173.  
  174. /*
  175.  * Private Procedures
  176.  */
  177.  
  178.  
  179. static void ClassInitialize()
  180. {
  181.  
  182.  
  183.  
  184. void GetGC(sw)
  185.     ScaleWidget sw;
  186. {
  187.     XGCValues values;
  188.     
  189.     values.foreground = sw->scale.foreground_pixel;
  190.     values.background = sw->core.background_pixel;
  191.     values.function = GXcopy;
  192.     
  193.     sw->scale.gc = XtGetGC((Widget) sw,
  194.                GCForeground | 
  195.                GCBackground | 
  196.                GCFunction,
  197.                &values);
  198. }
  199.  
  200.  
  201.  
  202. void Proportional();
  203.  
  204. void GetInitialScaleValues(sw)
  205.     ScaleWidget sw;
  206. {
  207.     if (sw->scale.proportional) {
  208.     sw->scale.scale_x = sw->scale.scale_y =
  209.         ((sw->scale.aspect_ratio > 1.0) ?
  210.          sw->scale.aspect_ratio : 1.0 / sw->scale.aspect_ratio) *
  211.          (sw->scale.precision > 1.0 ?
  212.           sw->scale.precision : 1.0);
  213.     Proportional(sw); /* need to cut them down to proper values */
  214.     }
  215.     else
  216.     sw->scale.scale_x = sw->scale.scale_y = 1.0;
  217. }
  218.  
  219.  
  220.  
  221. void GetRectangleBuffer(sw, buffer_size)
  222.     ScaleWidget sw;
  223.     Cardinal buffer_size;
  224.     /*
  225.      * This procedure will realloc a new rectangles buffer.
  226.      * If the new buffer size is less than nrectangles, some
  227.      * information will be lost.
  228.      */
  229. {
  230.     if (buffer_size == 0) {
  231.     buffer_size = DefaultBufferSize;
  232.     XtWarning("buffer size has to be a positive number greater than zero");
  233.     }
  234.     sw->scale.rectangles = (XRectangle *)
  235.     XtRealloc((char *) sw->scale.rectangles, 
  236.           buffer_size * sizeof(XRectangle));
  237.     sw->scale.buffer_size = buffer_size;
  238. }
  239.  
  240.  
  241.  
  242. /* ARGSUSED */
  243. static void Initialize(request, new)
  244.     Widget request, new;
  245. {
  246.     ScaleWidget new_sw = (ScaleWidget) new;
  247.     
  248.     new_sw->scale.table.x = (Position *) NULL;
  249.     new_sw->scale.table.y = (Position *) NULL;
  250.     new_sw->scale.table.width = (Dimension *) NULL;
  251.     new_sw->scale.table.height = (Dimension *) NULL;
  252.     
  253.     new_sw->scale.nrectangles = 0;
  254.     new_sw->scale.rectangles = (XRectangle *) NULL;
  255.     
  256.     GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  257.     
  258.     GetGC(new_sw);
  259.     
  260.     if (new_sw->scale.image != NULL) {
  261.     if (new_sw->core.width == 0)
  262.         new_sw->core.width = 
  263.         new_sw->scale.image->width + 2 * new_sw->scale.internal_width;
  264.     if (new_sw->core.height == 0)
  265.         new_sw->core.height = 
  266.         new_sw->scale.image->height + 2 *new_sw->scale.internal_height;
  267.     }
  268.     else {
  269.     if (new_sw->core.width == 0)
  270.         new_sw->core.width = 1 + 2 * new_sw->scale.internal_width;
  271.     if (new_sw->core.height == 0)
  272.         new_sw->core.height = 1 + 2 * new_sw->scale.internal_height;
  273.     new_sw->scale.image = XCreateImage(XtDisplay(new),
  274.                        DefaultVisual(XtDisplay(new), 
  275.                             DefaultScreen(XtDisplay(new))),
  276.                        1, XYBitmap, 0, 
  277.                        XtCalloc(1, sizeof(char)),
  278.                        1, 1, 8, 0);
  279.     }
  280.  
  281.     if ((new_sw->scale.aspect_ratio = 
  282.      atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  283.     new_sw->scale.aspect_ratio = 1.0;
  284.     XtWarning("AspectRatio has to be a positive number. (forced to 1.0)");
  285.     }
  286.  
  287.     if ((new_sw->scale.precision =
  288.          atof(new_sw->scale.precision_str)) < 0.0) {
  289.     new_sw->scale.precision = 0.001;
  290.     XtWarning("Precision has to be a positive number. (forced to 0.001)");
  291.     }
  292.     
  293.     if (new_sw->scale.scale_x_str == DefaultScaleFactor
  294.     || 
  295.     new_sw->scale.scale_y_str == DefaultScaleFactor)
  296.     GetInitialScaleValues(new_sw);
  297.     else {
  298.     if ((new_sw->scale.scale_x = 
  299.          atof(new_sw->scale.scale_x_str)) < 0.0) {
  300.         new_sw->scale.scale_x = 1.0;
  301.         XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  302.     }
  303.     if ((new_sw->scale.scale_y = 
  304.          atof(new_sw->scale.scale_y_str)) < 0.0) {
  305.         new_sw->scale.scale_y = 1.0;
  306.         XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  307.     }
  308.     }
  309. }
  310.  
  311.  
  312.  
  313. void BuildTable(sw)
  314.     ScaleWidget sw;
  315.     /* 
  316.      * This procedure builds scaling table for image in the scale struct
  317.      * Requires image, scale_x and scale_y to be set properly
  318.      */
  319. {
  320.     Position x, y;
  321.     
  322.     XtFree((char *) sw->scale.table.x);
  323.     XtFree((char *) sw->scale.table.y);
  324.     XtFree((char *) sw->scale.table.width);
  325.     XtFree((char *) sw->scale.table.height);
  326.     sw->scale.table.x = 
  327.     (Position *) XtMalloc(sizeof(Position) * sw->scale.image->width);
  328.     sw->scale.table.y = 
  329.     (Position *) XtMalloc(sizeof(Position) * sw->scale.image->height);
  330.     sw->scale.table.width = 
  331.     (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->width);
  332.     sw->scale.table.height = 
  333.     (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->height);
  334.     
  335.     /* Build the scaling table */    
  336.     for (x = 0; x < sw->scale.image->width; x++) {
  337.     sw->scale.table.x[(int) x] = (Position) myrint(sw->scale.scale_x * x);
  338.     sw->scale.table.width[(int) x] = (Dimension)
  339.         myrint(sw->scale.scale_x *(x + 1)) - myrint(sw->scale.scale_x * x);
  340.     }
  341.     for (y = 0; y < sw->scale.image->height; y++) {
  342.     sw->scale.table.y[(int) y] = (Position) myrint(sw->scale.scale_y * y);
  343.     sw->scale.table.height[(int) y] = (Dimension)
  344.         myrint(sw->scale.scale_y *(y + 1)) - myrint(sw->scale.scale_y * y);
  345.     }
  346. }
  347.  
  348.  
  349.  
  350. void FlushRectangles(sw, drawable, gc)
  351.     ScaleWidget sw;
  352.     Drawable drawable;
  353.     GC gc;
  354. {
  355.     XFillRectangles(XtDisplay(sw), drawable, gc, 
  356.             sw->scale.rectangles, sw->scale.nrectangles);
  357.     
  358.     sw->scale.nrectangles = 0;
  359. }
  360.  
  361.  
  362.  
  363. void FillRectangle(sw, drawable, gc, x, y, width, height)
  364.     ScaleWidget sw;
  365.     Drawable drawable;
  366.     GC gc;
  367.     Position x, y;
  368.     Dimension width, height;
  369. {
  370.     
  371.     if (sw->scale.nrectangles == sw->scale.buffer_size)
  372.     FlushRectangles(sw, drawable, gc);
  373.  
  374.     sw->scale.rectangles[(int) sw->scale.nrectangles].x = x;
  375.     sw->scale.rectangles[(int) sw->scale.nrectangles].y = y;
  376.     sw->scale.rectangles[(int) sw->scale.nrectangles].width = width;
  377.     sw->scale.rectangles[(int) sw->scale.nrectangles].height = height;
  378.  
  379.     ++sw->scale.nrectangles;
  380. }
  381.  
  382.  
  383.  
  384. void ScaleImage(sw, drawable, img_x, img_y, dst_x, dst_y, img_width,img_height)
  385.     ScaleWidget sw;
  386.     Drawable drawable;
  387.     Position img_x, img_y;
  388.     Position dst_x, dst_y;
  389.     Dimension img_width, img_height;
  390.     /* 
  391.      * This procedure scales image into the specified drawable
  392.      * It assumes scaling table was already built
  393.      */
  394. {
  395.     GC gc;
  396.     XGCValues gcv;
  397.     Position x, y;
  398.     Pixel pixel;
  399.     
  400.     /* Clip the img coordinates */
  401.     img_x = min(max(img_x, 0), (Position) sw->scale.image->width - 1);
  402.     img_y = min(max(img_y, 0), (Position) sw->scale.image->height - 1);
  403.     img_width = 
  404.       min(img_width, (Dimension)(sw->scale.image->width - (Dimension)img_x));
  405.     img_height = 
  406.       min(img_height, (Dimension)(sw->scale.image->height - (Dimension)img_y));
  407.  
  408.     if (sw->scale.scale_x == 1.0 && sw->scale.scale_y == 1.0) 
  409.     XPutImage(XtDisplay(sw), drawable, sw->scale.gc, sw->scale.image, 
  410.           img_x, img_y, dst_x, dst_y, 
  411.           img_width, img_height);
  412.     else {
  413.     dst_x = dst_x - sw->scale.table.x[(int) img_x];
  414.     dst_y = dst_y - sw->scale.table.y[(int) img_y];
  415.  
  416.     gc = XCreateGC(XtDisplay(sw), drawable, 0, NULL);
  417.  
  418.     gcv.function = GXcopy;
  419.     XChangeGC(XtDisplay(sw), gc, GCFunction, &gcv);
  420.  
  421.     /* make sure gc knows the right background */
  422.     gcv.background = sw->core.background_pixel;
  423.     XChangeGC(XtDisplay(sw), gc, GCBackground, &gcv);    
  424.  
  425.     /* Set the background of drawable.  If the most frequent color
  426.        is the background color it can speed up scaling process. */
  427.     gcv.foreground = gcv.background;
  428.     XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  429.     XFillRectangle(XtDisplay(sw), drawable, gc, 
  430.                sw->scale.table.x[(int) img_x] + dst_x, 
  431.                sw->scale.table.y[(int) img_y] + dst_y, 
  432.                sw->scale.table.x[(int) img_x + img_width - 1] - 
  433.                sw->scale.table.x[(int) img_x], 
  434.                sw->scale.table.y[(int) img_y + img_height - 1] - 
  435.                sw->scale.table.y[(int) img_y]);
  436.     
  437.     if (sw->scale.image->format == XYBitmap) {
  438.         for (x = img_x; x < img_x + (Position)img_width; x++)
  439.         for (y = img_y; y < img_y + (Position)img_height; y++) {
  440.             pixel = XGetPixel(sw->scale.image, x, y);
  441.             if (pixel) /* Do not draw background */
  442.             FillRectangle(sw, drawable, sw->scale.gc, 
  443.                       sw->scale.table.x[(int) x] + dst_x, 
  444.                       sw->scale.table.y[(int) y] + dst_y, 
  445.                       sw->scale.table.width[(int) x], 
  446.                       sw->scale.table.height[(int) y]);
  447.         }
  448.         FlushRectangles(sw, drawable, sw->scale.gc);
  449.     }
  450.     else {
  451.         for (x = img_x; x < img_x + (Position)img_width; x++)
  452.         for (y = img_y; y < img_y + (Position)img_height; y++) {
  453.             pixel = XGetPixel(sw->scale.image, x, y);
  454.             if (pixel != gcv.background) { /* Do not draw background */
  455.             if (gcv.foreground != pixel) { /* Change fg to pixel */
  456.                 gcv.foreground = pixel;
  457.                 XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  458.             }
  459.             XFillRectangle(XtDisplay(sw), drawable, gc,
  460.                        sw->scale.table.x[(int) x] + dst_x, 
  461.                        sw->scale.table.y[(int) y] + dst_y, 
  462.                        sw->scale.table.width[(int) x], 
  463.                        sw->scale.table.height[(int) y]);
  464.             }
  465.         }
  466.     }
  467.     XFreeGC(XtDisplay(sw), gc);
  468.     }
  469. }
  470.  
  471.  
  472.  
  473. int FindPixel(sw, x, y, img_x, img_y, img_pixel)
  474.     ScaleWidget sw;
  475.     Position x, y; /* (x,y) == (0,0) where image starts in sw window*/
  476.     Position *img_x, *img_y;
  477.     Pixel    *img_pixel;
  478. {
  479.     if (*img_x < 0 || *img_x >= sw->scale.image->width 
  480.     ||
  481.     *img_y < 0 || *img_y >= sw->scale.image->height)
  482.     return (-1);
  483.     
  484.     if (sw->scale.table.x[(int) *img_x] >= x) {
  485.     --*img_x;
  486.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  487.     }
  488.     if (sw->scale.table.x[(int) *img_x] + 
  489.     (Position)sw->scale.table.width[(int) *img_x] < x) {
  490.     ++*img_x;
  491.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  492.     }
  493.     if (sw->scale.table.y[(int) *img_y] >= y) {
  494.     --*img_y;
  495.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  496.     }
  497.     if (sw->scale.table.y[(int) *img_y] + 
  498.     (Position)sw->scale.table.height[(int) *img_y] < y) {
  499.     ++*img_y;
  500.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  501.     }
  502.     
  503.     *img_pixel = XGetPixel(sw->scale.image, *img_x, *img_y);
  504.     
  505.     return (0);
  506. }
  507.  
  508.  
  509.  
  510. int SWGetImagePixel(w, x, y, img_x, img_y, img_pixel)
  511.     Widget w;
  512.     Position x, y;
  513.     Position *img_x, *img_y;
  514.     Pixel    *img_pixel;
  515. {
  516.     ScaleWidget sw = (ScaleWidget) w;
  517.     
  518.     x -= sw->scale.x;
  519.     y -= sw->scale.y;
  520.     
  521.     *img_x = (Position) floor(x / sw->scale.scale_x);
  522.     *img_y = (Position) floor(y / sw->scale.scale_y);
  523.     
  524.     return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  525. }
  526.  
  527.  
  528.  
  529. /* ARGSUSED */
  530. static void Redisplay(w, event, region)
  531.     Widget w;
  532.     XEvent *event;
  533.     Region region;
  534. {
  535.     ScaleWidget sw = (ScaleWidget) w;
  536.     Position  x, y, img_x, img_y;
  537.     Dimension width, height;
  538.  
  539.     if (event->type == Expose) {
  540.  
  541.     if (event->xexpose.x < sw->scale.x) {
  542.         x = 0;
  543.         width = event->xexpose.width -
  544.         (sw->scale.x - event->xexpose.x);
  545.     }
  546.     else {
  547.         x = event->xexpose.x - sw->scale.x;
  548.         width = event->xexpose.width;
  549.     }
  550.     
  551.     if (event->xexpose.y < sw->scale.y) {
  552.         y = 0;
  553.         height = event->xexpose.height -
  554.         (sw->scale.y - event->xexpose.y);
  555.     }
  556.     else {
  557.         y = event->xexpose.y - sw->scale.y;
  558.         height = event->xexpose.height;
  559.     }
  560.     
  561.     img_x = min(max((Position) floor((float) x 
  562.                      / (float) sw->scale.scale_x), 0),
  563.             (Position) sw->scale.image->width - 1);
  564.  
  565.     img_y = min(max((Position) floor((float) y
  566.                      / (float) sw->scale.scale_y), 0),
  567.             (Position) sw->scale.image->height - 1);
  568.     
  569.     if (sw->core.visible) {  
  570.         ScaleImage(sw, XtWindow(w),
  571.                img_x, img_y,
  572.                sw->scale.x + sw->scale.table.x[(int) img_x],
  573.                sw->scale.y + sw->scale.table.y[(int) img_y],
  574.                (Dimension) ceil((float) width
  575.                     / sw->scale.scale_x) + 1, 
  576.                (Dimension) ceil((float) height
  577.                     / sw->scale.scale_y) + 1);
  578.     }
  579.     }
  580. }
  581.  
  582.  
  583.  
  584. void TryResize(sw)
  585.     ScaleWidget sw;
  586. {
  587.     Dimension width, height;
  588.     XtGeometryResult result;
  589.  
  590.     width = (Dimension) 
  591.     floor(sw->scale.image->width * sw->scale.scale_x)
  592.         + 2 * sw->scale.internal_width;
  593.     height = (Dimension) 
  594.     floor(sw->scale.image->height * sw->scale.scale_y)
  595.         + 2 * sw->scale.internal_height;
  596.     
  597.     while ((result =   
  598. /* SUPPRESS 530 */XtMakeResizeRequest((Widget)sw,width,height,&width,&height))
  599.        == XtGeometryAlmost);  
  600.     
  601.     if (result != XtGeometryNo) {
  602.     sw->core.width = width;
  603.     sw->core.height = height;
  604.     }
  605. }
  606.  
  607.  
  608.  
  609. void Precision(sw)
  610.     ScaleWidget sw;
  611. {
  612.     if (sw->scale.scale_x != 1.0)
  613.     sw->scale.scale_x = floor(sw->scale.scale_x / sw->scale.precision)
  614.                     * sw->scale.precision;
  615.  
  616.     if (sw->scale.scale_y != 1.0)
  617.     sw->scale.scale_y = floor(sw->scale.scale_y / sw->scale.precision)
  618.                 * sw->scale.precision;
  619. }
  620.  
  621.  
  622.  
  623. void Proportional(sw)
  624.     ScaleWidget sw;
  625. {
  626.     float scale_x, scale_y;
  627.  
  628.     scale_x = sw->scale.scale_y / sw->scale.aspect_ratio;
  629.     scale_y = sw->scale.scale_x * sw->scale.aspect_ratio;
  630.     
  631.     if (scale_x <= sw->scale.scale_x && scale_y <= sw->scale.scale_y) {
  632.     if (scale_x > scale_y)
  633.         sw->scale.scale_x = scale_x;
  634.     else
  635.         sw->scale.scale_y = scale_y;
  636.     }
  637.     else if (scale_x <= sw->scale.scale_x)
  638.     sw->scale.scale_x = scale_x;
  639.     else if (scale_y <= sw->scale.scale_y)
  640.     sw->scale.scale_y = scale_y;
  641.     else {
  642.     float x_ratio, y_ratio;
  643.     
  644.     x_ratio = scale_x / sw->scale.scale_x;
  645.     y_ratio = scale_y / sw->scale.scale_y;
  646.     
  647.     if (x_ratio < y_ratio)
  648.         sw->scale.scale_y /= x_ratio;
  649.     else
  650.         sw->scale.scale_x /= y_ratio;
  651.     }
  652.  
  653.     if (fabs(sw->scale.scale_x / sw->scale.scale_y * sw->scale.aspect_ratio 
  654.         - 1.0) > sw->scale.precision)
  655.     XtWarning("can not preserve aspect ratio");
  656. }
  657.  
  658.  
  659.  
  660. void GetScaledSize(sw)
  661.     ScaleWidget sw;
  662. {
  663.     sw->scale.width = (Dimension)
  664.     max(myrint(sw->scale.scale_x * sw->scale.image->width), 1);
  665.     sw->scale.height = (Dimension)
  666.     max(myrint(sw->scale.scale_y * sw->scale.image->height), 1);
  667. }
  668.  
  669.  
  670.  
  671. void GetScaleValues(sw)
  672.     ScaleWidget sw;
  673. {
  674.     /*
  675.      * Make sure to subtract internal width and height.
  676.      */
  677.     
  678.     sw->scale.scale_x = 
  679.     (float) max((int)(sw->core.width - 2 * sw->scale.internal_width), 1)
  680.         / (float) sw->scale.image->width;
  681.  
  682.     sw->scale.scale_y =
  683.     (float) max((int)(sw->core.height - 2 * sw->scale.internal_height), 1)
  684.         / (float) sw->scale.image->height;
  685. }
  686.  
  687.  
  688.  
  689. void Unscale(sw)
  690.     ScaleWidget sw;
  691. {
  692.     sw->scale.scale_x = sw->scale.scale_y = 1.0;
  693.  
  694.     GetScaledSize(sw);        
  695.     
  696.     BuildTable(sw);
  697. }
  698.  
  699.  
  700.  
  701. void Autoscale(sw)
  702.     ScaleWidget sw;
  703. {
  704.     GetScaleValues(sw);
  705.  
  706.     if (sw->scale.proportional) Proportional(sw);
  707.  
  708.     Precision(sw);
  709.  
  710.     GetScaledSize(sw);
  711.     
  712.     BuildTable(sw);
  713. }
  714.  
  715.  
  716.  
  717. void PositionImage(sw)
  718.     ScaleWidget sw;
  719. {
  720.     /*
  721.      * Set as if for ForgegGravity (that is center the image)
  722.      */
  723.     sw->scale.x = (Position) 
  724.     (sw->core.width - sw->scale.width) / 2;
  725.     sw->scale.y = (Position)
  726.     (sw->core.height - sw->scale.height) / 2;
  727.     
  728. /*****
  729.     if (sw->scale.gravity & WestGravity) { 
  730.     }
  731.     if (sw->scale.gravity & EastGravity) { 
  732.     }
  733.     if (sw->scale.gravity & NorthGravity) {
  734.     }
  735.     if (sw->scale.gravity & SouthGravity) {
  736.     }
  737. *****/
  738. }
  739.  
  740.  
  741.  
  742. static void Resize(w)
  743.     Widget w;
  744. {
  745.     ScaleWidget sw = (ScaleWidget) w;
  746.     
  747.     if (sw->scale.autoscale) Autoscale(sw);
  748.     
  749.     PositionImage(sw);
  750. }
  751.  
  752.  
  753.  
  754. static void Realize(wid, vmask, attr)
  755.         Widget wid;
  756.         Mask *vmask;
  757.         XSetWindowAttributes *attr;
  758. {
  759.   ScaleWidget sw = (ScaleWidget) wid;
  760.   XtCreateWindow(wid, (unsigned int) InputOutput,
  761.          (Visual *) sw->scale.visual, *vmask, attr);
  762. }
  763.  
  764.  
  765.  
  766. static void Destroy(w)
  767.     Widget w;
  768. {
  769.     ScaleWidget sw = (ScaleWidget) w; 
  770.  
  771.     XtFree((char *) sw->scale.table.x);
  772.     XtFree((char *) sw->scale.table.y);
  773.     XtFree((char *) sw->scale.table.width);
  774.     XtFree((char *) sw->scale.table.height);
  775.     
  776.     XtFree((char *) sw->scale.rectangles);
  777.  
  778.     XtReleaseGC(w, sw->scale.gc);
  779.  
  780.     XDestroyImage(sw->scale.image);
  781. }
  782.  
  783.  
  784.  
  785. /* ARGSUSED */
  786. static Boolean SetValues(current, request, new, args, num_args)
  787.     Widget current, request, new;
  788.     ArgList args;
  789.     Cardinal *num_args;
  790. {
  791.     ScaleWidget cur_sw = (ScaleWidget) current;
  792.     /* ScaleWidget req_sw = (ScaleWidget) request; */
  793.     ScaleWidget new_sw = (ScaleWidget) new;
  794.     Boolean redisplay = False;
  795.     int i;
  796.     
  797.     for (i = 0; i < *num_args; i++) {
  798.     if (streq(XtNbackground, args[i].name)) {
  799.         XSetBackground(XtDisplay(new), new_sw->scale.gc, 
  800.                new_sw->core.background_pixel);
  801.     }
  802.     if (streq(XtNforeground, args[i].name)) {
  803.         XSetForeground(XtDisplay(new), new_sw->scale.gc, 
  804.                new_sw->scale.foreground_pixel);
  805.     }
  806.     if (streq(XtNimage, args[i].name)) {
  807.         XDestroyImage(cur_sw->scale.image);
  808.         if (new_sw->scale.image == NULL)
  809.         new_sw->scale.image = XCreateImage(XtDisplay(new),
  810.                         DefaultVisual(XtDisplay(new), 
  811.                         DefaultScreen(XtDisplay(new))),
  812.                            1, XYBitmap, 0, 
  813.                            XtCalloc(1, sizeof(char)),
  814.                            1, 1, 8, 0);
  815.         else
  816.         new_sw->scale.image = 
  817.             XSubImage(new_sw->scale.image, 
  818.                   0, 0, 
  819.                   new_sw->scale.image->width, 
  820.                   new_sw->scale.image->height);
  821.  
  822.         if (new_sw->scale.resize)
  823.         TryResize(new_sw);
  824.         if (new_sw->scale.autoscale)
  825.         Autoscale(new_sw);
  826.         else {
  827.         GetScaledSize(new_sw);
  828.         BuildTable(new_sw);
  829.         }
  830.         PositionImage(new_sw);
  831.         redisplay = True;
  832.     }
  833.  
  834.     if (streq(XtNuserData, args[i].name)) 
  835.       new_sw->scale.userData = (XtPointer)args[i].value;
  836.  
  837.     if (streq(XtNbufferSize, args[i].name)) {
  838.         if (new_sw->scale.buffer_size != cur_sw->scale.buffer_size) {
  839.         GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  840.         }
  841.     }
  842.  
  843.     if (streq(XtNaspectRatio, args[i].name)) {
  844.         if ((new_sw->scale.aspect_ratio = 
  845.          atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  846.         new_sw->scale.aspect_ratio = cur_sw->scale.aspect_ratio;
  847.         XtWarning("AspectRatio has to be a positive number.");
  848.         }
  849.         else if (new_sw->scale.aspect_ratio != cur_sw->scale.aspect_ratio){
  850.         if (new_sw->scale.proportional) {
  851.             Proportional(new_sw);
  852.             Precision(new_sw);
  853.             GetScaledSize(new_sw);
  854.             BuildTable(new_sw);
  855.             PositionImage(new_sw);
  856.             redisplay = True;
  857.         }
  858.         }
  859.     }
  860.     
  861.     if (streq(XtNproportional, args[i].name)) {
  862.         if (new_sw->scale.proportional != cur_sw->scale.proportional) {
  863.         if (new_sw->scale.proportional) Proportional(new_sw);
  864.         Precision(new_sw);
  865.         GetScaledSize(new_sw);
  866.         BuildTable(new_sw);
  867.         PositionImage(new_sw);
  868.         redisplay = True;
  869.         }
  870.     }
  871.     
  872.     if (streq(XtNscaleX, args[i].name)
  873.         || 
  874.         streq(XtNscaleY, args[i].name)) {
  875.         if (new_sw->scale.scale_x_str == DefaultScaleFactor
  876.         || 
  877.         new_sw->scale.scale_y_str == DefaultScaleFactor)
  878.         GetInitialScaleValues(new_sw);
  879.         else {
  880.         if ((new_sw->scale.scale_x = 
  881.              atof(new_sw->scale.scale_x_str)) < 0.0) {
  882.             new_sw->scale.scale_x = cur_sw->scale.scale_x;
  883.             XtWarning("ScaleValue has to be a positive number.");
  884.         }
  885.         if ((new_sw->scale.scale_y = 
  886.              atof(new_sw->scale.scale_y_str)) < 0.0) {
  887.             new_sw->scale.scale_y = cur_sw->scale.scale_y;
  888.             XtWarning("ScaleValue has to be a positive number.");
  889.         }
  890.         }
  891.         if (new_sw->scale.scale_x != cur_sw->scale.scale_x
  892.         ||
  893.         new_sw->scale.scale_y != cur_sw->scale.scale_y) {
  894.         
  895.         /*?*?*?*?*?*?*?*?*?*?*?*?*?*?**?*?*?*?*?*?*?*?*?***?*/
  896.         fprintf(stderr, "================>>%f %f\n",
  897.             new_sw->scale.scale_x, new_sw->scale.scale_y);
  898.         
  899.         if (new_sw->scale.proportional) Proportional(new_sw);
  900.         Precision(new_sw);
  901.         if (new_sw->scale.resize)
  902.             TryResize(new_sw);
  903.         GetScaledSize(new_sw);        
  904.         BuildTable(new_sw);
  905.         PositionImage(new_sw);
  906.         redisplay = True;
  907.         }
  908.     }
  909.     
  910.     if (streq(XtNprecision, args[i].name)) {
  911.         if ((new_sw->scale.precision = 
  912.          atof(new_sw->scale.precision_str)) < 0.0) {
  913.         new_sw->scale.precision = cur_sw->scale.precision;
  914.         XtWarning("Precision has to be a positive number.");
  915.         }
  916.         if (new_sw->scale.precision != cur_sw->scale.precision) {
  917.         if (new_sw->scale.proportional) Proportional(new_sw);
  918.         Precision(new_sw);
  919.         GetScaledSize(new_sw);        
  920.         BuildTable(new_sw);
  921.         PositionImage(new_sw);
  922.         redisplay = True;
  923.         }
  924.     }
  925.     }            
  926.     return(redisplay);
  927. }
  928.  
  929.  
  930.  
  931. void SWUnscale(w)
  932.     Widget w;
  933. {
  934.     ScaleWidget sw = (ScaleWidget) w;
  935.  
  936.     Unscale(sw);
  937.     PositionImage(sw);
  938.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  939. }
  940.  
  941.  
  942.  
  943. void SWAutoscale(w)
  944.     Widget w;
  945. {
  946.     ScaleWidget sw = (ScaleWidget) w;
  947.  
  948.     Autoscale(sw);
  949.     PositionImage(sw);
  950.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  951. }
  952.  
  953.  
  954.  
  955. void SWInitialSize(w)
  956.     Widget w;
  957. {
  958.     ScaleWidget sw = (ScaleWidget) w;
  959.     
  960.     GetInitialScaleValues(sw);
  961.  
  962.     if (sw->scale.proportional) Proportional(sw);
  963.     Precision(sw);
  964.     if (sw->scale.resize)
  965.     TryResize(sw);
  966.     GetScaledSize(sw);        
  967.     BuildTable(sw);
  968.     PositionImage(sw);
  969.     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  970. }
  971.  
  972.  
  973.  
  974. void SWSetImage(w, image)
  975.     Widget w;
  976.     XImage *image;
  977. {
  978.     int n;
  979.     Arg wargs[2];
  980.     
  981.     n = 0;
  982.     XtSetArg(wargs[n], XtNimage, (XtArgVal) image); n++;
  983.     XtSetValues(w, wargs, n);
  984. }
  985.  
  986.  
  987.  
  988. extern void SWRequestSelection();
  989.  
  990. void RequestSelection(w, event)
  991.     Widget w;
  992.     XEvent *event;
  993. {
  994.     SWRequestSelection(w, event->xbutton.time);
  995. }
  996.  
  997.  
  998.  
  999. extern void SWGrabSelection();
  1000.  
  1001. void GrabSelection(w, event)
  1002.     Widget w;
  1003.     XEvent *event;
  1004. {
  1005.     SWGrabSelection(w, event->xbutton.time);
  1006. }
  1007.  
  1008.  
  1009.  
  1010. Pixmap SWGetPixmap(w)
  1011.     Widget w;
  1012. {
  1013.     ScaleWidget sw = (ScaleWidget) w;
  1014.     Pixmap pixmap;
  1015.  
  1016.     pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w), 
  1017.                sw->scale.width, 
  1018.                sw->scale.height, 
  1019.                sw->scale.image->depth);
  1020.     ScaleImage(sw, pixmap, 
  1021.            0, 0, 0, 0, 
  1022.            (Dimension) sw->scale.image->width, 
  1023.            (Dimension) sw->scale.image->height);
  1024.     
  1025.     return(pixmap);
  1026. }
  1027.